package com.czk.volatiles;

import java.util.concurrent.TimeUnit;

/**
 * 内存可见性的测试
 * 缓存一致性协议：MESI Modify 修改 Exclusive独享 Share 共享 Invalid 无效状态
 * 多个cpu从主内存读取同一个数据到各自的高速缓存，当其中某个cpu修改了缓存里的数据，改数据会马上同步到主内存
 * 其他cpu通过总线嗅探机制可以感觉到数据的变化从而将自己缓存里的数据失效
 *
 * @Author:ChenZhangKun
 * @Date: 2021/3/30 17:08
 */
public class VolatileVisibilityTest {
    /**
     * 没有volatile则线程二不会立即刷新到主存，导致线程一空转
     * 底层主要是汇编的lock前缀指令
     * lock前缀指令的作用：
     * 1 会将当前处理器的缓存行的数据立即写回到系统内存
     * 2 写回内存的操作会引起在其他cpu缓存了该内存的地址的数据无效（MESI）协议
     * 3 提供内存屏障功能，lock前后得到指令不能重排序
     */
    private static volatile boolean initFlag = false;

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            System.out.println("waiting data");
            // 内存空转
            // 线程一会将initFlag从主内存读到工作内存->对应的底层操作是read操作
            // 然后底层load加载到工作内存
            // 然后进行use操作
            // 然后assign进行赋值操作
            // 然后store操作
            // 然后进行write操作到主内存
            while (!initFlag) {
            }
            System.out.println("get data");
        }).start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> prepareData()).start();


    }

    /**
     * 改变值
     */
    private static void prepareData() {
        System.out.println("prepare data");
        initFlag = true;
        System.out.println("prepare data end");
    }
}
